#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <asm/uaccess.h>  
#include <linux/kernel.h>
#include <linux/fs.h>
#include<linux/sched.h>
#include <linux/slab.h>
#include <linux/list_sort.h>

#define MESSAGE_LENGTH 2048
static char Message[MESSAGE_LENGTH];
static char *pchar=0;
static int globcount=0;

int cmp1(void *, struct list_head*, struct list_head*);

int cmp2(void *, struct list_head *, struct list_head *);

int cmp3(void *, struct list_head *, struct list_head *);

int cmp4(void *, struct list_head *, struct list_head *);

struct mystruct
{
	struct task_struct task_list;
	struct list_head list;
};


struct mystruct *head=0;

struct list_head *my_list_start(struct list_head *paramhead,
	       		 		 loff_t *pos)
{
	//printk("pos %d", *pos);
	struct list_head *myiter=head->list.prev;
	if(*pos<globcount)
	{
		int i;
		for(i=0;i<*pos;i++)
			myiter=myiter->prev;
		return myiter;
	}
	
	else
		return NULL;
}

static void *my_seq_next(struct seq_file *s, void *v, loff_t *pos)
{
	struct list_head *tmp=0;
	tmp=v;
	tmp=tmp->prev;
	(*pos)++;
	if(tmp!=(&head->list))
		return tmp;
	else
		return 0;
	//struct mystruct *val;
/*	(*pos)++;
	if(v)
	{
		tmp=v;		
		tmp=tmp->prev;
		if(tmp)
		{		
			val=list_entry (tmp, struct mystruct, list);
			printk("next work pid %d name %s prev %p \n",val->task_list.pid, val->task_list.comm, tmp->prev);
		}
	}*/
	
	
}
	

static int my_seq_show(struct seq_file *s, void *v)
{
	struct list_head *tmp=v;
	struct mystruct *val=list_entry (tmp, struct mystruct, list);
	seq_printf(s, "pid %d task %s\n", val->task_list.pid, val->task_list.comm);
	return 0;
}

static void my_list_stop(struct seq_file *s, void *v)
	{
	        
	}
static const struct seq_operations my_seq_ops = {
	        .start = my_list_start,
	        .next  = my_seq_next,
	        .stop  = my_list_stop,
	        .show  = my_seq_show
};







int myinitdata()
{
	int i=0;
	
	struct mystruct *tmp;
	struct mystruct	*tail;
	struct task_struct *task_list;
	struct list_head *p;
	struct list_head *j;
	head=(struct mystruct*)kmalloc(sizeof(struct mystruct), GFP_KERNEL);
	INIT_LIST_HEAD(&(head->list));
	
	for_each_process(task_list)
	{
		
		
		tail=(struct mystruct*)kmalloc(sizeof(struct mystruct), GFP_KERNEL);
		tail->task_list.pid=task_list->pid;
		strcpy(tail->task_list.comm,task_list->comm);
		list_add(&(tail->list), &(head->list));
		
	}
	globcount=0;
	list_for_each(p, &head->list)
	{
		tmp = list_entry (p, struct mystruct, list);
		globcount++;
		//printk("pid %d  task %s ponter %p\n", tmp->task_list.pid, tmp->task_list.comm, tmp->list.prev);
		//j=&(tmp->list);
	}
	//j->next=0;
	//j->prev=0;
	//sprintf(Message, "aaaaa :%d", count);
	//count++;
	
	return 0;
}



static int myopen(struct inode *inode, struct  file *file)
{
	pchar=Message;
	seq_open(file, &my_seq_ops);
	return 0;
}



static int myread(struct file *filp, char *buffer, size_t length, loff_t * offset)
{
	int i=0;
	
	for(i=0;i<length&&*pchar;i++)
	{
		put_user(*pchar,buffer+i);
		pchar++;
	}
	
	return i;
}



static int mywrite(struct file *filp, const char *buff, size_t len, loff_t * off)
{
	int i;
	struct mystruct *tmp;
	struct list_head *p;
	for (i = 0; i < MESSAGE_LENGTH - 1 && i < len; i++)
		get_user(Message[i], buff + i);
	Message[i] = '\0';
	if(!(strcmp(Message,"refresh\n")))
	{
		myinitdata();
		printk("myinit\n");
	}
	if(!(strcmp(Message,"straight\n")))
	{
		myinitdata();
		printk("myinit\n");
		list_sort(0, &(head->list), cmp1);
		list_for_each(p, &head->list)
		{
			tmp = list_entry (p, struct mystruct, list);
			//printk("straight work pid %d  task %s ponter %p\n", tmp->task_list.pid, tmp->task_list.comm, tmp->list.prev);
		//j=&(tmp->list);
		}
	}
	if(!(strcmp(Message,"reverse\n")))
	{
		myinitdata();
		printk("myinit\n");
		list_sort(0, &(head->list), cmp2);
		list_for_each(p, &head->list)
		{
			tmp = list_entry (p, struct mystruct, list);
			//printk("reverse work pid %d  task %s ponter %p\n", tmp->task_list.pid, tmp->task_list.comm, tmp->list.prev);
		//j=&(tmp->list);
		}
	}
	if(!(strcmp(Message,"abc\n")))
	{
		myinitdata();
		printk("myinit\n");
		list_sort(0, &(head->list), cmp3);
		list_for_each(p, &head->list)
		{
			tmp = list_entry (p, struct mystruct, list);
			//printk("write work pid %d  task %s ponter %p\n", tmp->task_list.pid, tmp->task_list.comm, tmp->list.prev);
		//j=&(tmp->list);
		}
	}
	if(!(strcmp(Message,"zyx\n")))
	{
		myinitdata();
		printk("myinit\n");
		list_sort(0, &(head->list), cmp4);
	}	
	return i;
}



static struct file_operations myhandlers={
	.owner = THIS_MODULE,	
	.read=seq_read,
	.open=myopen,
	.write=mywrite
	
};

int init_module()
{
	proc_create("snapshot", 0, NULL, &myhandlers);
	myinitdata();
	return 0;
}


void cleanup_module()
{
	remove_proc_entry("snapshot", 0);
}



int cmp1(void * priv, struct list_head *a, struct list_head *b)
{
	
	struct mystruct *val1;
	struct mystruct *val2;
	val1=list_entry (a, struct mystruct, list);
	val2=list_entry (b, struct mystruct, list);
	//printk("cmp1 work pid %d \n ",val1->task_list.pid);
	if(val1->task_list.pid > val2->task_list.pid)
		return 1;
	else if(val1->task_list.pid < val2->task_list.pid)
		return -1;
	else
		return 0;
}



int cmp2(void * priv, struct list_head *a, struct list_head *b)
{
	
	struct mystruct *val1;
	struct mystruct *val2;
	val1=list_entry (a, struct mystruct, list);
	val2=list_entry (b, struct mystruct, list);
	//printk("cmp1 work pid %d \n ",val1->task_list.pid);
	if(val1->task_list.pid > val2->task_list.pid)
		return -1;
	else if(val1->task_list.pid < val2->task_list.pid)
		return 1;
	else
		return 0;
}
int cmp3(void * priv, struct list_head *a, struct list_head *b)
{
	
	struct mystruct *val1;
	struct mystruct *val2;
	val1=list_entry (a, struct mystruct, list);
	val2=list_entry (b, struct mystruct, list);
	//printk("cmp1 work pid %d \n ",val1->task_list.pid);
	return strcmp(val1->task_list.comm, val2->task_list.comm);
	
}
int cmp4(void * priv, struct list_head *a, struct list_head *b)
{
	
	int i=0;	
	struct mystruct *val1;
	struct mystruct *val2;
	val1=list_entry (a, struct mystruct, list);
	val2=list_entry (b, struct mystruct, list);
	//printk("cmp1 work pid %d \n ",val1->task_list.pid);
	i=strcmp(val1->task_list.comm, val2->task_list.comm);
	return (-1)*i;
	
}


